//*****************************************************************************
//
// Author		: Konstantin Chizhov
// Date			: 2013
// All rights reserved.

// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.

// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//*****************************************************************************

#pragma once
#include <stdint.h>

namespace Mcucpp
{

	class RxTxCount
	{
		size_t _readCount;
		size_t _writeCount;
	public:
		RxTxCount()
		{
			 Reset();
		}
		void IncRx() {_readCount++; }

		void IncTx() {_writeCount++; }

		size_t Read() { return _readCount; }
		
		size_t Written() { return _writeCount;}
		
		void ResetRead() { _readCount = 0; }
		
		void ResetWritten()	{ _writeCount = 0; }
		
		void Reset()
		{
			_readCount = 0;
			_writeCount = 0;
		}
	} Count;
	
	template<class Source>
	class ReadWriteCounterAdapter :public Source
	{
		Source &_source;
	public:
		ReadWriteCounterAdapter(Source &source)
			:_source(source)
		{}
		
		uint8_t Read()
		{
			uint8_t c = _source.Read();
			Count.IncRx();
			return c;
		}
		
		void Write(uint8_t c)
		{
			_source.Write(c);
			Count.IncTx();
		}
		
		RxTxCount Count;
	};
	
	template<class Source>
	class ReadWriteCounterMixin :public Source
	{
	public:
		template<class T1>
		ReadWriteCounterMixin(T1 arg1)
			:Source(arg1)
		{
		}

		template<class T1, class T2>
		ReadWriteCounterMixin(T1 arg1, T2 arg2)
			:Source(arg1, arg2)
		{
		}

		template<class T1, class T2, class T3>
		ReadWriteCounterMixin(T1 arg1, T2 arg2, T3 arg3)
			:Source(arg1, arg2, arg3)
		{
		}
		
		uint8_t Read()
		{
			uint8_t c = Source::Read();
			Count.IncRx();
			return c;
		}
		
		void Write(uint8_t c)
		{
			Source::Write(c);
			Count.IncTx();
		}
		
		RxTxCount Count;
	};
}
